#ifndef _H_CUTIL_H_
#define _H_CUTIL_H_

#include "../typedefine.h"
#include "ENetErrorCode.h"
#if _WIN32
#include <WinSock2.h>
#else
#include <fcntl.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#endif

#ifndef INVALID_SOCKET
#define INVALID_SOCKET -1
#endif
#if !_WIN32
typedef int SOCKET;
#endif
#ifndef SOCKET_ERROR
#define SOCKET_ERROR -1
#endif

namespace TB
{
    inline ENetErrorCode GetLastError()
    {
#if _WIN32
        return (ENetErrorCode)WSAGetLastError();
#else
        auto nErrNo = errno;
        switch (nErrNo)
        {
        case EPERM:
            return ENetErrorCode::AccessDenied;
        case ENOENT:
            return ENetErrorCode::AddressNotAvailable;
        case EBADF:
            return ENetErrorCode::OperationAborted;
        case ENFILE:
            return ENetErrorCode::TooManyOpenSockets;
        default:
            return (ENetErrorCode)nErrNo;
        }
#endif
    }

    inline SOCKET CreateSocket()
    {
#if _WIN32
        SOCKET nSocketFD = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
#else
        SOCKET nSocketFD = socket(AF_INET, SOCK_STREAM, 0);
#endif
        if (nSocketFD == INVALID_SOCKET)
        {
            return nSocketFD;
        }
#if _WIN32
        u_long qwMode = 1;
        if (NO_ERROR != ioctlsocket(nSocketFD, FIONBIO, &qwMode))
        {
            closesocket(nSocketFD);
            return INVALID_SOCKET;
        }
#else
        int opt = fcntl(nSocketFD, F_GETFL);
        if (0 > opt)
        {
            close(nSocketFD);
            return INVALID_SOCKET;
        }
        opt |= O_NONBLOCK;
        if (0 != fcntl(nSocketFD, F_SETFL, opt))
        {
            close(nSocketFD);
            return INVALID_SOCKET;
        }
#endif
        return nSocketFD;
    }

    inline void CloseSocket(SOCKET socket)
    {
#if _WIN32
        closesocket(socket);
#else
        close(socket);
#endif
    }

    inline bool SetNonBlock(SOCKET socket)
    {
#if _WIN32
        u_long qwMode = 1;
        if (NO_ERROR != ioctlsocket(socket, FIONBIO, &qwMode))
            return false;
#else
        int opt = fcntl(socket, F_GETFL);
        if (0 > opt)
        {
            return false;
        }
        opt |= O_NONBLOCK;
        if (0 != fcntl(socket, F_SETFL, opt))
            return false;
#endif
        return true;
    }
}

#endif